package com.github.ecbp.user.service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.ecbp.common.constant.ConstantCode;
import com.github.ecbp.common.data.entity.BaseEntity;
import com.github.ecbp.common.data.service.impl.BaseServiceImpl;
import com.github.ecbp.common.data.utils.TransformUtils;
import com.github.ecbp.common.req.BaseIdDTO;
import com.github.ecbp.common.resp.NameVo;
import com.github.ecbp.common.security.vo.DefaultUserPermission;
import com.github.ecbp.common.utils.Asserts;
import com.github.ecbp.user.service.common.UserCodeAndMessageEnum;
import com.github.ecbp.user.service.dto.PermissionDto;
import com.github.ecbp.user.service.entity.*;
import com.github.ecbp.user.service.mapper.PermissionMapper;
import com.github.ecbp.user.service.mapper.PermissionMenuRelationMapper;
import com.github.ecbp.user.service.response.PermissionRes;
import com.github.ecbp.user.service.service.*;
import com.github.ecbp.user.service.vo.AdminRoleIdVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 后台资源表 服务实现类
 * </p>
 *
 * @author zj2626
 * @since 2020-03-18
 */
@Service
public class PermissionServiceImpl extends BaseServiceImpl<PermissionMapper, TPermission> implements PermissionService {
    @Autowired
    private RoleService roleService;
    @Autowired
    private AdminRoleRelationService adminRoleRelationService;
    @Autowired
    private RoleMenuRelationService roleMenuRelationService;
    @Autowired
    private PermissionMenuRelationService permissionMenuRelationService;
    @Autowired
    private RolePermissionRelationService rolePermissionRelationService;
    @Autowired
    private ResourceService resourceService;
    @Autowired
    private PermissionMenuRelationMapper permissionMenuRelationMapper;

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int create(PermissionDto param) {
        TPermission permission = TransformUtils.copy(param, TPermission.class);
        Asserts.checkNotNull(super.save(permission), UserCodeAndMessageEnum.MENU_PERMISSION_SAVE_ERROR);

        TPermissionMenuRelation permissionMenuRelation = new TPermissionMenuRelation();
        permissionMenuRelation.setMenuId(param.getMenuId());
        permissionMenuRelation.setPermissionId(permission.getId());
        permissionMenuRelationService.saveBase(permissionMenuRelation);

        Asserts.isTrue(updateResource(param, permission.getId()), UserCodeAndMessageEnum.MENU_PERMISSION_SAVE_ERROR);
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean updateById(PermissionDto param) {
        removeRelation(param.getId());

        TPermission permission = TransformUtils.copy(param, TPermission.class);
        Asserts.checkNotNull(super.updateById(permission), UserCodeAndMessageEnum.MENU_PERMISSION_SAVE_ERROR);

        TPermissionMenuRelation permissionMenuRelation = new TPermissionMenuRelation();
        permissionMenuRelation.setMenuId(param.getMenuId());
        permissionMenuRelation.setPermissionId(permission.getId());
        permissionMenuRelationService.saveBase(permissionMenuRelation);

        Asserts.isTrue(updateResource(param, permission.getId()), UserCodeAndMessageEnum.MENU_PERMISSION_SAVE_ERROR);
        return true;
    }

    private boolean updateResource(PermissionDto param, Long id) {
        LambdaUpdateWrapper<TResource> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TResource::getPermissionId, id);
        updateWrapper.set(TResource::getPermissionId, null);
        updateWrapper.set(TResource::getPermissionStatus, ConstantCode.FALSE);
        resourceService.update(null, updateWrapper);

        if (!CollectionUtils.isEmpty(param.getResourceIds())) {
            LambdaUpdateWrapper<TResource> updateWrapper2 = new LambdaUpdateWrapper<>();
            updateWrapper2.in(TResource::getId, param.getResourceIds());
            updateWrapper2.set(TResource::getPermissionId, id);
            updateWrapper2.set(TResource::getPermissionStatus, ConstantCode.TRUE);
            return resourceService.update(null, updateWrapper2);
        }
        return true;
    }

    private void removeRelation(Long id) {
        // 先删除原来的关系
        LambdaQueryWrapper<TPermissionMenuRelation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TPermissionMenuRelation::getPermissionId, id);
        permissionMenuRelationMapper.deleteWithFill(new TPermissionMenuRelation(), wrapper);
    }

    @Override
    public NameVo listDefault() {
        LambdaQueryWrapper<TPermission> wrapper = new LambdaQueryWrapper<>(getEntityClass());
        wrapper.select(TPermission::getId, TPermission::getName);
        wrapper.eq(TPermission::getStatus, ConstantCode.TRUE);
        wrapper.orderByAsc(TPermission::getCreateTime);
        wrapper.last("limit 1");
        final TPermission tPermissions = baseMapper.selectOne(wrapper);
        return TransformUtils.copy(tPermissions, NameVo.class);
    }

    @Override
    public PermissionRes getById(Long id) {
        PermissionRes vo = TransformUtils.copy(baseMapper.selectById(id), PermissionRes.class);
        if (null == vo) {
            return null;
        }
        final List<TMenu> menu = permissionMenuRelationService.getMenuByPermissionId(vo.getId());
        if (!CollectionUtils.isEmpty(menu)) {
            vo.setMenuId(CollectionUtils.isEmpty(menu) ? null : menu.get(0).getId());
        }

        vo.setResourceList(resourceService.listByPermissionId(new BaseIdDTO(vo.getId())));

        return vo;
    }

    @Override
    public List<TPermission> getPermissionList(Long adminId, DefaultUserPermission userPermission) {
        List<AdminRoleIdVo> adminRoleIdVos = adminRoleRelationService.getRoleIdByAdminId(adminId);
        if (CollectionUtils.isEmpty(adminRoleIdVos)) {
            return Collections.emptyList();
        }
        Set<Long> roleIds = adminRoleIdVos.stream().map(AdminRoleIdVo::getRoleId).collect(Collectors.toSet());
        userPermission.setRoles(roleIds);

        final List<TMenu> menuByRoleIds = roleMenuRelationService.getMenuByRoleId(roleIds);
        if (CollectionUtils.isEmpty(menuByRoleIds)) {
            return Collections.emptyList();
        }
        final Set<Long> menuIds = menuByRoleIds.stream().map(BaseEntity::getId).collect(Collectors.toSet());
        userPermission.setMenus(menuIds);

        final List<TPermission> permissionByMenuIds = permissionMenuRelationService.getPermissionByMenuId(menuIds);
        if (CollectionUtils.isEmpty(permissionByMenuIds)) {
            return Collections.emptyList();
        }
        final Set<Long> permissionIds = permissionByMenuIds.stream().map(BaseEntity::getId).collect(Collectors.toSet());
        userPermission.setPermissions(permissionIds);

        return new ArrayList<>(permissionByMenuIds);
    }

    /**
     * 重新加载权限相关的用户的权限信息
     *
     * @param ids
     */
    @Override
    public void reloadUserPermission(Set<Long> ids) {
        final List<TRole> roleByPermissionId = rolePermissionRelationService.getRoleByPermissionId(ids);
        if (!CollectionUtils.isEmpty(roleByPermissionId)) {
            Set<Long> roleIds = roleByPermissionId.stream().map(BaseEntity::getId).collect(Collectors.toSet());
            roleService.reloadUserPermission(roleIds);
        }
    }

    @Override
    protected void assemble(TPermission entity, LambdaQueryWrapper<TPermission> wrapper) {
        super.assemble(entity, wrapper);
        if (!StringUtils.isEmpty(entity.getTitle())) {
            wrapper.likeRight(TPermission::getTitle, entity.getTitle());
        }
        if (!StringUtils.isEmpty(entity.getName())) {
            wrapper.likeRight(TPermission::getName, entity.getName());
        }
        if (!StringUtils.isEmpty(entity.getPower())) {
            wrapper.likeRight(TPermission::getPower, entity.getPower());
        }
        wrapper.orderByDesc(BaseEntity::getCreateTime);
    }
}
